﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Microsoft.Crm.SdkTypeProxy;
using Microsoft.Crm.Sdk.Query;
using Microsoft.Crm.Sdk;
using System.Configuration;
using System.Net;

namespace Infusion.CRM.Attachments
{
    public class Helper
    {
        public string FileName { get; set; }
        public string EntityName { get; set; }
        public string EntityGuidField { get; set; }
        public string EntityGuidValue { get; set; }
        public string AltIdName { get; set; }
        public string AltValue { get; set; }
        public string Description { get; set; }
        public string Title { get; set; }

        public Helper(string fileName, string entityName, string entityGuidField, string entityGuidValue, string altIdName,
            string altValue, string description, string title)
        {
            this.FileName = fileName;
            this.EntityName = entityName;
            this.EntityGuidField = entityGuidField;
            this.EntityGuidValue = entityGuidValue;
            this.AltIdName = altIdName;
            this.AltValue = altValue;
            this.Description = description;
            this.Title = title;
        }

        private string ReadFile()
        {
            byte[] data;
            using (FileStream fs = File.OpenRead(FileName))
            {
                data = new byte[fs.Length];
                int offset = 0;
                int remaining = data.Length;
                while (remaining > 0)
                {
                    int read = fs.Read(data, offset, remaining);
                    if (read <= 0)
                    {
                        throw new EndOfStreamException(String.Format("End of stream reached with {0} bytes left to read", remaining));
                    }
                    remaining -= read;
                    offset += read;
                }
            }

            return Convert.ToBase64String(data);
        }

        public Guid GetEntityGuid(CrmService svc)
        {
            if (!string.IsNullOrEmpty(EntityGuidValue))
            {
                return new Guid(EntityGuidValue);
            }
            else
            {
                ConditionExpression condition = new ConditionExpression();
                condition.AttributeName = AltIdName;
                condition.Operator = ConditionOperator.Equal;
                condition.Values = new object[] { AltValue };

                QueryExpression query = new QueryExpression();
                query.EntityName = EntityName;
                query.ColumnSet = new AllColumns();
                query.Criteria.Conditions.Add(condition);

                RetrieveMultipleRequest retrieveRequest = new RetrieveMultipleRequest();
                retrieveRequest.Query = query;
                retrieveRequest.ReturnDynamicEntities = true;
                RetrieveMultipleResponse retrieveResponse = (RetrieveMultipleResponse)svc.Execute(retrieveRequest);

                BusinessEntityCollection retrieved = retrieveResponse.BusinessEntityCollection;
                if (retrieved.BusinessEntities.Count == 0)
                {
                    throw new ApplicationException("Record not found");
                }
                DynamicEntity de = (DynamicEntity)retrieved.BusinessEntities[0];
                Key key = (Key)de.Properties[EntityGuidField];
                return key.Value;
            }
        }

        public Guid Attach()
        {
            string b64 = ReadFile();
            CrmService svc = GetService();

            annotation note = new annotation();
            note.subject = Title;
            note.notetext = Description;
            note.filename = Path.GetFileName(FileName);
            note.documentbody = b64;
            note.objectid = new Lookup();
            note.objectid.type = EntityName;
            note.objectid.Value = GetEntityGuid(svc);
            note.objecttypecode = new EntityNameReference();
            note.objecttypecode.Value = EntityName;

            return svc.Create(note);
        }

        private CrmService GetService()
        {
            CrmService svc = new CrmService();

            CrmAuthenticationToken token = new CrmAuthenticationToken();
            token.AuthenticationType = 0;
            token.OrganizationName = ConfigurationSettings.AppSettings["Organization Name"];

            string domain = ConfigurationSettings.AppSettings["User Domain"];
            string username = ConfigurationSettings.AppSettings["User Name"];
            string pwd = ConfigurationSettings.AppSettings["User Password"];
            svc.Credentials = new NetworkCredential(username, pwd, domain);
            svc.CrmAuthenticationTokenValue = token;
            svc.Url = ConfigurationSettings.AppSettings["CRM Web Service Url"];

            return svc;
        }

    }
}
